#include <kern/spinlock.h>
#include <kern/debug.h>
#include <kern/proc.h>
#include <string.h>
#include <x86.h>


void initlock(struct spinlock_t* l)
{
	memset(l, 0, sizeof *l);
}

void acquire(struct spinlock_t* l)
{
	pushcli();
	while(xchg(&l->locked, 1) != 0);
}

void release(struct spinlock_t* l)
{
	xchg(&l->locked, 0);
	popcli();
}

void pushcli(void)
{
	// TODO remember original interrupt state (enable or disable)
	// use eflag register with IF flag for this
	int eflags = read_eflags();

	cli();
	if (!cpu->ncli)
		cpu->interrupt_enabled = eflags & FL_IF;
	++cpu->ncli;
}

void popcli(void)
{
	ASSERT(cpu->ncli > 0, "popcli too many times");
	--cpu->ncli;
	if (!cpu->ncli && cpu->interrupt_enabled)
		sti();
}

